package database

import (
	"fmt"
	"gitee.com/ichub/goconfig/common/base/baseutils/goutils"
	"gitee.com/ichub/goconfig/common/ichubcache"
	"gitee.com/ichub/goconfig/common/ichubconfig"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	"sync"

	//_ "github.com/jinzhu/gorm/dialects/sqlite"
	"gitee.com/ichub/goconfig/common/base/baseconfig"
	"gitee.com/ichub/goconfig/common/base/baseconsts"
	"gitee.com/ichub/goconfig/common/base/basedto"
	"github.com/sirupsen/logrus"
	"time"
)

/*
@Title    文件名称: ichubclient.go
@Description  描述: 代码工厂数据库配置信息
@Author  作者: leijianming@163.com  时间(2024-03-13 22:38:21)
@Update  作者: leijianming@163.com  时间(2024-03-13 22:38:21)
*/
func FindDbClient(dto *baseconfig.DbClientDto) *IchubDbClient {

	if md, ok := ichubcache.FindBeanMetaCache().CacheGetType(dto, "DbClientDto"); ok {
		return md.(*IchubDbClient)
	}
	var dbcli = Default()
	dbcli.DbClientDto = dto
	var err = dbcli.IniDb()
	if err != nil {
		logrus.Error(err)
	}

	return ichubcache.FindMetaCacheSet[IchubDbClient](dbcli)

}

type FuncGetDb func() *gorm.DB

var rw sync.RWMutex
var dbCli *IchubDbClient

func DbCli() *IchubDbClient {
	if dbCli == nil {
		dbCli = Default()
	}
	return dbCli
}

func GetDB() (*gorm.DB, error) {

	if DbCli().Db == nil {
		rw.Lock()
		defer rw.Unlock()
		if _, err := Ini(); err != nil {
			return nil, err
		}
	}
	return DbCli().DbDebug(), nil
}

func Ini() (*gorm.DB, error) {

	DbCli().DbClientDto = ichubconfig.FindBeanIchubConfig().ReadIchubDb()
	var err = DbCli().IniDb()
	if err != nil {
		logrus.Error(err)
		return nil, err

	}
	if ichubconfig.FindBeanIchubConfig().Gorm.Debug == "true" {
		return DbCli().DbDebug(), nil
	}
	return DbCli().Db, nil

}

type IchubDbClient struct {
	basedto.BaseEntity
	Db *gorm.DB `json:"-"`

	*baseconfig.DbClientDto
}

func NewIchubDbClient() *IchubDbClient {

	return Default()
}
func Default() *IchubDbClient {
	var dbclient = &IchubDbClient{}
	dbclient.InitProxy(dbclient)
	if dbclient.DbClientDto == nil {
		dbclient.DbClientDto = ichubconfig.FindBeanIchubConfig().ReadIchubDb()
	}
	dbclient.DbClientDto.InitProxy(dbclient.IchubClientDto)
	return dbclient
}

func (this *IchubDbClient) DbDebug() *gorm.DB {
	return this.Db.Debug()
}

func (this *IchubDbClient) ValueOf(dto *baseconfig.DbClientDto) {
	this.DbClientDto = dto //copier.Copy(this, dto)
}

// DbUrl:"host=192.168.13.235 port=26257 user=code  password=123456  dbname=" + configdto.ModuleDefineInst.Dbname + " sslmode=require",
func (this *IchubDbClient) MakeDbUrl() (dburl string) {

	if this.Dbtype == baseconsts.DB_TYPE_MYSQL {
		return this.MakeDbUrlMysql()
	}
	if len(this.Password) > 0 {
		return this.MakeDbUrlPostgres()
	}
	return this.MakeDbUrlPostgres()
}

func (this *IchubDbClient) MakeDbUrlSsl() (dburl string) {

	if this.Dbtype == baseconsts.DB_TYPE_MYSQL {
		return this.MakeDbUrlMysql()
	}
	return this.MakeDbUrlPostgres()
}

func (this *IchubDbClient) MakeDbUrlMysql() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&mb4&parseTime=True&loc=Local",
		this.Username,
		this.Password,
		this.Host,
		this.Port,

		this.Dbname)
}

func (this *IchubDbClient) MakeDbUrlPostgres() string {

	return fmt.Sprintf(
		"postgresql://%s:%s@%s:%s/%s?sslmode=disable",

		this.Username,
		this.Password,
		this.Host,
		this.Port,
		this.Dbname)

}

//DbUrl:        "host=192.168.13.235 port=26257 user=code  password=123456  dbname=" + configdto.ModuleDefineInst.Dbname + " sslmode=require",

func (this *IchubDbClient) MakeDbUrlCockRoach() string {
	//DbUrl:   ssmode=disable", require disable
	return fmt.Sprintf(
		"postgresql://%s:%s@%s:%s/%s?sslmode=%s",

		this.Username,
		this.Password,
		this.Host,
		this.Port,
		this.Dbname,
		this.Sslmode)

}

func (this *IchubDbClient) Log() (dburl string) {
	dburl = this.MakeDbUrl()
	logrus.Info(this.MakeDbUrl())
	return
}
func (this *IchubDbClient) InitDbMysql(conn string) (*gorm.DB, error) {
	logrus.Info(conn)
	db, err := gorm.Open(baseconsts.DB_TYPE_MYSQL, conn)
	if err != nil {
		logrus.Error("Failed to connect mysql database, err:", err.Error(), conn)
		return nil, err
	}
	var gormClientDto = this.GormClient
	db.DB().SetMaxOpenConns(this.Str2Int(gormClientDto.MaxOpenConns))
	db.DB().SetMaxIdleConns(this.Str2Int(gormClientDto.MaxIdleConns))
	db.DB().SetConnMaxLifetime(time.Duration(this.Str2Int(gormClientDto.MaxLifetime)) * time.Second)
	return db, err
}

func (this *IchubDbClient) InitDbPostgres(conn string) (db *gorm.DB, err error) {

	db, err = gorm.Open(baseconsts.DB_TYPE_POSTGRES, conn)
	if err != nil {
		logrus.Error("InitDbPostgres 连接postgres失败!", conn, err)
		return nil, err
	}
	if err = db.DB().Ping(); err != nil {
		logrus.Fatalln(err)
		return db, err
	}
	var client = this.GormClient
	db.DB().SetMaxOpenConns(this.Str2Int(client.MaxOpenConns))
	db.DB().SetMaxIdleConns(this.Str2Int(client.MaxIdleConns))
	db.DB().SetConnMaxLifetime(time.Duration(this.Str2Int(client.MaxLifetime)) * time.Second)

	return db, err
}

func (this *IchubDbClient) GetDb() *gorm.DB {
	return this.Db
}

func (this *IchubDbClient) Valueof(ds *baseconfig.DbClientDto) {
	this.DbClientDto = ds //copier.Copy(this, ds)
}

func (this *IchubDbClient) IniDb() error {

	var err error
	switch this.Dbtype {
	case baseconsts.DB_TYPE_MYSQL:
		this.Db, err = this.InitDbMysql(this.MakeDbUrlMysql())
	case baseconsts.DB_TYPE_POSTGRES:
		this.Db, err = this.InitDbPostgres(this.MakeDbUrlPostgres())

	case baseconsts.DB_TYPE_COCKROACH:
		this.Db, err = this.InitDbPostgres(this.MakeDbUrlCockRoach())

	}
	if err != nil {
		goutils.Error(err)
	}
	return err
}
